#include "PitchFinder.h"

#include <QCoreApplication>
#include <fftw/fftw++.h>
#include <QFile>
#include <QString>
#include <QAudioInput>
#include <QAudioFormat>
#include <QTimerEvent>
#include <QDataStream>
#include <QTimer>
#include <QTime>
#include <QObject>
#include <iostream>

using namespace fftwpp;

PitchFinder::PitchFinder(QObject * parent) :
	QObject(parent),
	fileName("sample.raw"),
	dataFile(fileName),
	frequency(8000),
	numSamples(1024),
	Forward(numSamples, -1),
	currMax(0),
	recording(false)
{
	dt = 1.0/(double)frequency;
	df = 1.0/double(numSamples)/dt;

	inputArray = new quint16[numSamples];
	fftArray = ComplexAlign(numSamples);

	format.setFrequency(frequency);
	format.setChannels(1);
	format.setSampleSize(16);
	format.setCodec("audio/pcm");
	format.setByteOrder(QAudioFormat::LittleEndian);
	format.setSampleType(QAudioFormat::Float);

	QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
	if (!info.isFormatSupported(format))
	{
		format = info.nearestFormat(format);
	}

	recorder = new QAudioInput(format, this);
	recorder->setNotifyInterval(sampleTime);
}

PitchFinder::~PitchFinder()
{
	return;
}

int PitchFinder::GetPeakIndex()
{
	double maxValue = 0;
	int index = -1;

	dataFile.open(QIODevice::ReadOnly);
	audioData.setDevice(&dataFile);
	audioData.setByteOrder(QDataStream::LittleEndian);

	for (int i = 0; i < numSamples; i++)
	{
		audioData >> inputArray[i];
		fftArray[i] = (Complex)inputArray[i];
	}

	dataFile.close();

	Forward.fftNormalized(fftArray);

	double re;
	double im;
	double norm;
	for (int i = 0; i < numSamples/2; i++)
	{
		//std::cout << fftArray[i] << "\t" << i << std::endl;
		re = fftArray[i].real();
		im = fftArray[i].imag();

		norm = sqrt(re*re + im*im);

		if (i > 20 && norm > 70 && norm > maxValue)
		{
			maxValue = norm;
			index = i;
			//std::cout << norm << "\t" << df*i << std::endl;
		}
	}

	return index;
}

void PitchFinder::SetPitch()
{
	recorder->stop();
	dataFile.close();

	int index = GetPeakIndex();
	currMax = (double)index*(df)/2.0;
	emit(PitchFound(currMax));
}

void PitchFinder::Record()
{
	if (dataFile.exists())
		dataFile.remove();
	dataFile.open(QIODevice::WriteOnly);
	recorder->start(&dataFile);
}

double PitchFinder::GetPitch()
{
	Record();
	return currMax;
}


